<template>
  <transition name="result">
    <div class="result" v-show="visible">
      <div id="siri-container" ref="siriwave" class="siriwave"></div>
      <!-- 识别中 -->
      <p class="recognize-status">识别中<span class="dotting"></span></p>
      <!-- 识别结果 or 匹配结果 -->
      <div class="result-text">
        <p class="recognized-text" ref="recognizedText" :class="{ 'match-text': isShowMatched }"></p>
      </div>
      <!-- 未开始识别 or 没有匹配结果 -->
      <div class="commander-tip">
        <span>您可以这样说：</span>
        <span class="tips-text">{{ randomTips }}</span>
      </div>
    </div>
  </transition>
</template>
<script>
import SiriWave from 'siriwave'
import EventBus from '@/assets/js/app/cmlpanel/util/bus.js'
import { voiceRecognizeServer as vrs, soundServer as ss } from 'anov-core'
import {
  suggestCmd,
  suggestTester
} from '../../../../config/command/suggestCmd'

let wave = null
export default {
  name: 'Result',
  components: {},
  model: {},
  props: {},
  data() {
    return {
      visible: false,
      result: '',
      status: '',
      commands: [
        '使用默认主题',
        '上一个主题',
        '下一个主题',
        '切换语言',
        '使用中文',
        '使用英文',
        '开启音效',
        '关闭音效',
        '切换背景音效',
        '第一个菜单',
        '打开系统设置',
        '关闭系统设置',
        '打开项目设置',
        '关闭项目设置',
        '打开开发者',
        '关闭开发者',
        '打开控制面板',
        '关闭控制面板',
        '开启语音提示',
        '关闭语音提示',
        '开启人脸识别',
        '关闭人脸识别',
        '开启手势识别',
        '关闭手势识别',
        '开启语音识别',
        '关闭语音识别',
        '开启光感识别',
        '关闭光感识别',
        '开启动画调试',
        '关闭动画调试',
        '切换到本地数据源',
        '切换到远程数据源',
        ...suggestCmd
      ],
      testCmd: [
        ...suggestTester,
        /主题/i,
        /(语言|中文|英文)/i,
        /(音效|音乐)/i,
        /菜单/i,
        /语音/i,
        /人脸/i,
        /手势/i,
        /光感/i,
        /数据/i,
        /设置/i,
        /打开/i,
        /开启/i,
        /关闭/i,
        /一个/i,
        /使用/i,
        /切换/i,
        /系统/i,
        /动画/i,
        /设置/i
      ],
      randomTips: '',
      isShowMatched: false
    }
  },
  computed: {},
  watch: {},
  created() {},
  mounted() {
    wave = new SiriWave({
      container: this.$refs.siriwave,
      width: 320,
      height: 80,
      style: 'ios9',
      speed: 0.4,
      amplitude: 0.01, //波纹高度
      autostart: true
    })
    // 生成随机提示
    this.randomTips = this.getRandomTips()
    // 绑定事件
    EventBus.$on('voiceReconginzeStateChange', (state, data) => {
      switch (state) {
        // 识别结束
        case 'result':
          // 暂停识别
          // vrs.pause()
          // this.showOrHideStatus(false)
          /* typeof data 'array' 识别结束
            typeof data object 匹配正确指令
            data.result 识别结果
            data.tag 正则表达式
            data.params 提取的参数 [params1, params2, params3]
          */
          if (Array.isArray(data)) {
            // 生成提示
            this.randomTips = this.getMatchedTips(data) ? this.getMatchedTips(data):this.getRandomTips()
            // 显示提示
            this.showOrHideTip(true)
            // 识别结果
            TweenMax.to('.recognized-text', 0.5, {
              opacity: 1,
              scrambleText: {
                text: data[0] || 'b',
                chars: data[1] || '_',
                speed: 0.3,
                ease: Linear.easeNone
              }
            })
            TweenMax.to('.recognized-text', 0, {
              delay: 5,
              scrambleText: {
                text: '',
                speed: 0
              },
              opacity: 0
            })
            // setTimeout(() => {
            //   vrs.resume()
            // }, 3000)
          } else {
            // 添加音效
            ss.play({ type: 'matched' })
            this.isShowMatched = true
            // 匹配成功 获取匹配的句子
            let matchedText
            const { params, result, tag } = data
            for (let i = 0; i < result.length; i++) {
              let isMatched = tag.test(result[i])
              tag.lastIndex = 0
              if (isMatched) {
                matchedText = result[i]
                break
              }
            }
            // 动画
            TweenMax.to('.recognized-text', 0.5, {
              opacity: 1,
              scrambleText: {
                text: matchedText || 'a',
                chars: result[0] || '_',
                speed: 0.3,
                ease: Linear.easeNone
              }
            })
            // TweenMax.to('.recognized-text', 0, {
            //   delay: 5,
            //   scrambleText: {
            //     text: '',
            //     speed: 0
            //   },
            //   opacity: 0,
            //   onComplete: () => {
            //     // 动画结束,继续语音识别
            //     this.isShowMatched = false
            //   }
            // })
            setTimeout(() => {
              this.$refs.recognizedText.innerHTML = ''
              this.isShowMatched = false
            }, 5000)
            
            // setTimeout(() => {
            //   vrs.resume()
            // }, 3000)
          }
          wave.setAmplitude(0.01)
          break
        case 'start':
          wave.setAmplitude(0.01)
          break
        case 'soundstart':
          // 隐藏提示
          this.showOrHideTip(false)
          // 显示识别状态
          // this.showOrHideStatus(true)
          wave.setAmplitude(2.5)
          break
        case 'abort':
          this.result = ''
          wave.setAmplitude(0.01)
          break
      }
    })
  },
  beforeDestroy() {
    wave.stop()
    wave = null
  },
  methods: {
    // 关闭
    doClose() {
      if (!this.visible) return
      this.visible = false
    },
    // 获取3个随机提示
    getRandomTips() {
      let tip = [],
        len = this.commands.length
      for (let i = 0; i < 3; i++) {
        tip.push(this.commands[parseInt(Math.random() * len, 10)])
      }
      return tip.join('，')
    },
    // 获取相似度高的提示
    getMatchedTips(results) {
      let tip = []
      for (let i = 0; i < results.length; i++) {
        for (let j = 0; j < this.testCmd.length; j++) {
          let isMatched = this.testCmd[j].test(results[i])
          if (isMatched) {
            for (let k = 0; k < this.commands.length; k++) {
              let isCommandMatched = this.testCmd[j].test(this.commands[k])
              if (isCommandMatched) {
                tip.push(this.commands[k])
              }
            }
          }
        }
      }
      let sortedArr = this.uniqAndSortByTimes(tip)
      // todo 整理tip
      let tipLen = sortedArr.length
      if (tipLen === 0) {
        return this.getRandomTips()
      } else if (tipLen > 3) {
        return sortedArr.slice(0, 3).join('，')
      }
      return sortedArr.join('，')
    },
    // 提示显示/隐藏控制
    showOrHideTip(isShow = true) {
      if (isShow) {
        TweenMax.to('.commander-tip', 0.5, {
          delay: 0,
          css: {
            height: '27px',
            opacity: 1
          }
        })
        TweenMax.to('.commander-tip', 0.5, {
          delay: 3,
          css: {
            height: 0,
            opacity: 0
          }
        })
      } else {
        TweenMax.to('.commander-tip', 0.2, {
          css: {
            height: 0,
            opacity: 0
          },
          onComplete: () => {}
        })
      }
    },
    // 状态显示/隐藏控制
    showOrHideStatus(isShow = true) {
      if (isShow) {
        TweenMax.to('.recognize-status', 0.3, {
          css: {
            height: '27px',
            opacity: 1
          },
          ease: Linear.easeNone
        })
        TweenMax.to('.recognize-status', 0.3, {
          delay: 5,
          css: {
            height: 0,
            opacity: 0
          }
        })
      } else {
        TweenMax.to('.recognize-status', 0.3, {
          css: {
            height: 0,
            opacity: 0
          },
          ease: Linear.easeNone
        })
      }
    },
    uniqAndSortByTimes(arr) {
      let cacheArr = []
      function drop(arr) {
        let first = arr.shift(),
          len = 1
        for (let i = 0; i < arr.length; i++) {
          if (arr[i] === first) {
            len += 1
            arr.splice(i, 1)
            i -= 1
          }
        }
        cacheArr.push({
          len,
          value: first
        })
        if (arr.length) {
          drop(arr)
        }
      }
      drop(arr)
      cacheArr.sort((a, b) => {
        if (a.len < b.len) {
          return 1
        }
        if (a.len > b.len) {
          return -1
        }
        return 0
      })
      let finalArr = []
      for (let j = 0; j < cacheArr.length; j++) {
        finalArr.push(cacheArr[j].value)
      }
      return finalArr
    }
  }
}
</script>
<style lang="scss" scoped>
.result {
  overflow: hidden;

  position: absolute;
  bottom: 0;
  left: 50%;

  width: 800px;
  height: 160px;
  border-radius: 250px/120px 120px 0 0;

  background: #0009;

  box-shadow: 0 0 100px 60px #0009;

  transform: translateX(-50%);
  .siriwave {
    width: 100%;
    height: 80px;

    text-align: center;
  }
  .recognize-status {
    height: 0;

    opacity: 0;

    text-align: center;
  }
  .result-text {
    color: #42cad7;
    .recognized-text {
      text-align: center;
    }
    .match-text {
      // color: #50e839;
      &:after {
        content: ']';
      }
      &:before {
        content: '[';
      }
    }
  }
  .commander-tip {
    text-align: center;
  }
}
.result-enter {
  height: 0;

  opacity: 0;
}
.result-enter-to {
  height: 160px;

  opacity: 1;
}
.result-enter-active {
  transition: all ease 0.2s;
}
.result-leave {
  height: 160px;

  opacity: 1;
}
.result-leave-to {
  height: 0;

  opacity: 0;
}
.result-leave-active {
  transition: all ease 0.2s;
}
// dotting 效果实现
.dotting {
  display: inline-block;

  min-width: 2px;
  min-height: 2px;

  box-shadow: 2px 0 currentColor, 6px 0 currentColor, 10px 0 currentColor;

  animation: dot 2s infinite step-start both;
}
.dotting:before {
  content: '...';
} /* IE8 */
.dotting::before {
  content: '';
}
:root .dotting {
  margin-right: 8px;
} /* IE9+,FF,CH,OP,SF */

@-webkit-keyframes dot {
  25% {
    box-shadow: none;
  }
  50% {
    box-shadow: 2px 0 currentColor;
  }
  75% {
    box-shadow: 2px 0 currentColor, 6px 0 currentColor;
  }
}
@keyframes dot {
  25% {
    box-shadow: none;
  }
  50% {
    box-shadow: 2px 0 currentColor;
  }
  75% {
    box-shadow: 2px 0 currentColor, 6px 0 currentColor;
  }
}
</style>
